using System;
using System.Collections.Generic;
using System.Text;
using org.ngwt.user.client.rpc;

namespace org.ngwt.user.client.rpc.impl
{
    /**
     * Base class for the client and server serialization streams. This class
     * handles the basic serialization and deserialization formatting for primitive
     * types since these are common between the client and the server.
     */
    public abstract class AbstractSerializationStreamWriter
        : AbstractSerializationStream, SerializationStreamWriter
    {
          public abstract String toString();

          public void writeBoolean(Boolean fieldValue) {
            append(fieldValue ? "1" : "0");
          }

          public void writeByte(byte fieldValue) {
            append(fieldValue.ToString());
          }

          public void writeChar(char ch) {
            // just use an int, it's more foolproof
            append(((int)ch).ToString());
          }

          public void writeDouble(double fieldValue) {
            append(fieldValue.ToString());
          }

          public void writeFloat(float fieldValue) {
            append(fieldValue.ToString());
          }

          public void writeInt(int fieldValue) {
            append(fieldValue.ToString());
          }

          public void writeLong(long fieldValue) {
            append(fieldValue.ToString());
          }


          public void writeObject(Object instance,Type clazz)
          {
              if (instance == null)
              {
                  // write a null string
                  writeString(null);
                  return;
              }

              int objIndex = getIndexForObject(instance);
              if (objIndex >= 0)
              {
                  // We've already encoded this object, make a backref
                  // Transform 0-based to negative 1-based
                  writeInt(-(objIndex + 1));
                  return;
              }

              saveIndexForObject(instance);

              if(clazz == null)
              {
                  // Serialize the type signature
                  String typeSignature = getObjectTypeSignature(instance);
                  writeString(typeSignature);
                  // Now serialize the rest of the object
                  serialize(instance, typeSignature);
              }
              else
              {
                  String typeSignature = getTypeSignature(clazz);
                  writeString(typeSignature);
                  // Now serialize the rest of the object
                  serialize(instance, typeSignature, clazz);
              }

          }
          public void writeObject(Object instance) {
              writeObject(instance, null);
          }

          public void writeShort(short value) {
            append(value.ToString());
          }

          public void writeString(String value) {
            writeInt(addString(value));
          }
          /**
           * Add a string to the string table and return its index.
           * 
           * @param string the string to add
           * @return the index to the string
           */
          protected abstract int addString(String str);

          /**
           * Append a token to the underlying output buffer.
           * 
           * @param token the token to append
           */
          protected abstract void append(String token);

          /**
           * Get the index for an object that may have previously been saved via
           * {@link #saveIndexForObject(Object)}.
           * 
           * @param instance the object to save
           * @return the index associated with this object, or -1 if this object hasn't
           *         been seen before
           */
          protected abstract int getIndexForObject(Object instance);

          /**
           * Compute and return the type signature for an object.
           * 
           * @param instance the instance to inspect
           * @return the type signature of the instance
           */
          protected abstract String getObjectTypeSignature(Object instance);

          protected abstract String getTypeSignature(Type clazz);

          /**
           * Remember this object as having been seen before.
           * 
           * @param instance the object to remember
           */
          protected abstract void saveIndexForObject(Object instance);

          /**
           * Serialize an object into the stream.
           * 
           * @param instance the object to serialize
           * @param typeSignature the type signature of the object
           * @throws SerializationException
           */
          protected abstract void serialize(Object instance, String typeSignature);

          protected abstract void serialize(object instance, string typeSignature, Type clazz);

    }
}
